from model import *

MONTHS = {'JAN': 1, 'FEB': 2, 'MAR': 3, 'APR': 4, 'MAY': 5, 'JUN': 6, 'JUL': 7, 'AUG': 8, 'SEP': 9, 'OCT': 10, 'NOV': 11, 'DEC':12}

class Handler:

    def __init__(self):
        self.currentlevel = -1
        self.objectstack = []
        self.familyTree = None
        self.objects = {'INDI': {}, 'FAM':{}, 'SOUR': {}, 'NOTE': {}, 'SUBM': {}, 'ASSO': {}}

    def read_individual(self, ident):
        individual = None
        # test if individual is present in list of individuals already read
        if ident in self.objects['INDI']:
            individual = self.objects['INDI'][ident]
        else:
            individual = Individual(ident)
            self.objects['INDI'][ident] = individual
        self.objectstack.append(individual)
        self.familyTree.individuals.append(individual)
        return individual

    def read_family(self, ident):
        family = None
        if ident in self.objects['FAM']:
            family = self.objects['FAM'][ident]
        else:
            family = Family(ident)
            self.objects['FAM'][ident] = family
        self.objectstack.append(family)
        self.familyTree.families.append(family)
        return family

    def read_source(self, ident):
        source = None
        if ident in self.objects['SOUR']:
            source = self.objects['SOUR'][ident]
        else:
            source = Source(ident)
            self.objects['SOUR'][ident] = source
        self.objectstack.append(source)
        self.familyTree.sources.append(source)
        return source

    def read_note(self, ident, text):
        note = None
        if ident != None:
            if ident in self.objects['NOTE']:
                note = self.objects['NOTE'][ident]
            else:
                note = Note(ident)
                self.objects['NOTE'][ident] = note
            self.objectstack.append(note)
            self.familyTree.notes.append(note)
        else:
            note = Note(None)
            self.objectstack[-1].notes.append(note)
            self.objectstack.append(note)
        if text != None:
            note.text = text
        return note

    def read_submitter(self, ident):
        source = None
        if ident in self.objects['SUBM']:
            submitter = self.objects['SUBM'][ident]
        else:
            submitter = Submitter(ident)
            self.objects['SUBM'][ident] = submitter
        self.objectstack.append(submitter)
        self.familyTree.submitters.append(submitter)
        return submitter

    def read_date(self, value):
        date = self.objectstack[-1].geddate = GedDate()
        self.parse_date(date, value)
        self.objectstack[-1].geddate = date
        self.objectstack.append(date)

    def parse_date(self, date, line):
        dateline = line
        # read mode
        if line.find('BEF.') >= 0:
            date.mode = 'before'
            self.parse_simple_date(date, line[5:])           
        elif line.find('AFT.') >= 0:
            date.mode = 'after'
            self.parse_simple_date(date, line[5:])           
        elif line.find('BET.') >= 0:
            date.mode = 'between'
            elements = line[5:].rsplit('-')
            # beginning
            beginning_date = GedDate()
            self.parse_simple_date(beginning_date, elements[0].strip())  
            date.beginning = beginning_date
            # end
            end_date = GedDate()
            self.parse_simple_date(end_date, elements[1].strip())
            date.end = end_date
        elif line.find('CAL.') >= 0:
            date.mode = 'calculated'
            self.parse_simple_date(date, line[5:])           
        elif line.find('EST.') >= 0:
            date.mode = 'estimated'
            self.parse_simple_date(date, line[5:])           
        elif line.find('ABT.') >= 0:
            date.mode = 'about'
            self.parse_simple_date(date, line[5:])
        else:
            date.mode = 'simple'
            self.parse_simple_date(date, line)
        
    def parse_simple_date(self, date, line):
        elements = line.rsplit(' ')
        if len(elements) == 1:
            date.year = int(elements[0])
            date.month = None
            date.day = None
        elif len(elements) == 2:
            date.month = MONTHS[elements[0].upper()]
            date.year = int(elements[1])
            date.day = None
        elif len(elements) == 3:
            date.year = int(elements[2])
            date.month = MONTHS[elements[1].upper()]
            date.day = int(elements[0])

    def read_time(self, value):
        date = self.objectstack[-1]
        self.parse_time(date, value)

    def parse_time(self, date, line):
        elements = line.rsplit(':')
        date.hour = int(elements[0])
        date.minute = int(elements[1])
        date.seconde = int(elements[2])

    def handle_continue(self, text):
        value = '\n'
        if text != None:
            value = '\n' + text
        self.handle_concat_continue(value)
        
    def handle_concat(self, text):
        self.handle_concat_continue(text)
    
    def handle_concat_continue(self, text):
        if type(self.objectstack[-1]) is Address:
            self.objectstack[-1].text = self.objectstack[-1].text + text
        elif len(self.objectstack) > 1 and self.objectstack[-1] == 'FILE':
            self.objectstack[-2].filename = self.objectstack[-2].filename + text
        elif len(self.objectstack) > 1 and self.objectstack[-1] == 'TITL':
            self.objectstack[-2].title = self.objectstack[-2].title + text
        elif len(self.objectstack) > 1 and self.objectstack[-1] == 'TEXT':
            self.objectstack[-2].text = self.objectstack[-2].text + text
        elif len(self.objectstack) > 1 and self.objectstack[-1] == 'AUTH':
            self.objectstack[-2].originator = self.objectstack[-2].originator + text
        elif len(self.objectstack) > 1 and self.objectstack[-1] == 'PUBL':
            self.objectstack[-2].publication = self.objectstack[-2].publication + text
        else:
            self.objectstack[-1].text = self.objectstack[-1].text + text
        self.objectstack.append(text)
        
        
    def handle_name(self, personal_name):
        if type(self.objectstack[-1]) == Submitter:
            self.objectstack[-1].name = personal_name
            self.objectstack.append(personal_name)
        else:
            name = Individual_Name()
            self.objectstack[-1].names.append(name)
            self.objectstack[-1].personal_name = personal_name
            self.objectstack.append(name)
        
    def handle_address(self, address_line):
        address = self.objectstack[-1].address = Address()
        self.objectstack.append(address)
        if address_line != None:
            address.text = address_line
        
    def handle_address_postal_code(self, postal_code):
        self.objectstack[-1].postal_code = postal_code
        self.objectstack.append(postal_code)
        
    def handle_address_line1(self, address_line1):
        self.objectstack[-1].address_line1 = address_line1
        self.objectstack.append(address_line1)

    def handle_address_line2(self, address_line2):
        self.objectstack[-1].address_line2 = address_line2
        self.objectstack.append(address_line2)

    def handle_address_city(self, city):
        self.objectstack[-1].city = city
        self.objectstack.append(city)

    def handle_address_state(self, state):
        self.objectstack[-1].state = state
        self.objectstack.append(state)

    def handle_address_contry(self, contry):
        self.objectstack[-1].contry = contry
        self.objectstack.append(contry)

    def handle_phone_number(self, phone_number):
        phone = self.objectstack[-1].phone_number = PhoneNumber()
        self.objectstack.append(phone)
        if phone_number != None:
            phone.value = phone_number
            
    def handle_asso(self, ident):
        association = None
        # test if association is present in list of associations already read
        if ident != None:
            if ident in self.objects['ASSO']:
                association = self.objects['ASSO'][ident]
            else:
                association = Association()
                association.ident = ident
                self.objects['ASSO'][ident] = association
        else:
            association = Association()
        self.objectstack[-1].associations.append(association)
        self.objectstack.append(association)
        
    def handle_type(self, type):
        self.objectstack[-1].type = type
        self.objectstack.append(type)

    def handle_relation(self, relation):
        self.objectstack[-1].relation = relation
        self.objectstack.append(relation)
        
    def handle_change_date(self):
        change = Change()
        self.objectstack[-1].change = change
        self.objectstack.append(change)
        
    def handle_family_child_pedigree(self, pedigree):
        self.objectstack[-1].pedigree = pedigree
        self.objectstack.append(pedigree)
        
    def handle_family_child(self, ident):
        family = self.read_family(ident)
        #self.objectstack[-2].familychildren.append(family)
        
    def handle_event_age(self, age):
        self.objectstack[-1].age = age
        self.objectstack.append(age)

    def handle_event_responsible_agency(self, responsible_agency):
        self.objectstack[-1].responsible_agency = responsible_agency
        self.objectstack.append(responsible_agency)

    def handle_event_cause(self, cause):
        self.objectstack[-1].cause = cause
        self.objectstack.append(cause)
        
    def handle_event(self, type):
        event = Event()
        event.type = type
        self.objectstack[-1].events.append(event)
        self.objectstack.append(event)
        
    def handle_individual_sex(self, value):
        self.objectstack[-1].sex = value
        self.objectstack.append(value)

    def handle_header_version(self, version):
        self.objectstack[-1].version = version
        self.objectstack.append(version)

    def handle_filename(self, filename):
        self.objectstack[-1].filename = filename
        self.objectstack.append('FILE')

    def handle_text(self, text):
        self.objectstack[-1].text = text
        self.objectstack.append('TEXT')

    def handle_originator(self, originator):
        self.objectstack[-1].originator = originator
        self.objectstack.append('AUTH')

    def handle_publication(self, publication):
        self.objectstack[-1].publication = publication
        self.objectstack.append('PUBL')

    def handle(self, tuple):
        # All line except end of file
        # detect end of object description by a level decrease
        if (tuple[1] != 'TRLR'):
            # when the processed tuple have a level lesser than the current level
            # we finish to work on current object
            while tuple[0] <= self.currentlevel:
                poped = self.objectstack.pop()
                self.currentlevel = self.currentlevel - 1
            self.currentlevel = tuple[0]

        # Start of file
        # ######################################################################
        # All level
        # ######################################################################
        # Header specific structure elements
        if tuple[1] == 'VERS':
            self.handle_header_version(tuple[3])
        # Address specific structure elements
        elif tuple[1] == 'ADDR':
            self.handle_address(tuple[3])
        elif tuple[1] == 'ADR1':
            self.handle_address_line1(tuple[3])
        elif tuple[1] == 'ADR2':
            self.handle_address_line2(tuple[3])
        elif tuple[1] == 'CITY':
            self.handle_address_city(tuple[3])
        elif tuple[1] == 'STAE':
            self.handle_address_state(tuple[3])
        elif tuple[1] == 'POST':
            self.handle_address_postal_code(tuple[3])
        elif tuple[1] == 'CTRY':
            self.handle_address_contry(tuple[3])
        elif tuple[1] == 'PHON':
            self.handle_phone_number(tuple[3])
        # Association specific structure elements
        elif tuple[1] == 'ASSO':
            self.handle_asso(tuple[2])
        elif tuple[1] == 'TYPE':            # also for event
            self.handle_type(tuple[3])
        elif tuple[1] == 'RELA':
            self.handle_relation(tuple[3])
        # Change date specific structure elements
        elif tuple[1] == 'CHAN':
            self.handle_change_date()
        # Child to family specific structure elements
        elif tuple[1] == 'FAMC':
            self.handle_family_child(tuple[2])
        elif tuple[1] == 'PEDI':
            self.handle_family_child_pedigree()
        # Event specific structure elements
        elif tuple[1] == 'AGE':
            self.handle_event_age(tuple[3])
        elif tuple[1] == 'AGNC':
            self.handle_event_responsible_agency(tuple[3])
        elif tuple[1] == 'CAUS':
            self.handle_event_cause(tuple[3])
        # Family events specific structure elements
        elif tuple[1] in ('ANUL', 'CENS', 'DIV', 'DIVF', 'ENGA', 'MARR', 'MARB', 'MARC', 'MARL', 'MARS', 'EVEN'):
            self.handle_event(tuple[1])
        # Individual attributes specific structure elements
        # TODO
        elif tuple[1] == 'SEX':
            self.handle_individual_sex(tuple[3])
        # Individual events specific structure elements
        elif tuple[1] in ('BIRT', 'CHR', 'DEAT', 'BURI', 'CREM', 'ADOP', 'BAPM', 'BARM', 'BASM', 'BLES', 'CHRA', 'CONF', 'FCOM', 'ORDN', 'NATU', 'EMIG', 'IMMI', 'CENS', 'PROB', 'WILL', 'GRAD', 'RETI', 'EVEN'):
            self.handle_event(tuple[1])

        # others
        elif tuple[1] == 'DATE':
            self.read_date(tuple[3])
        elif tuple[1] == 'TITL':
            self.objectstack[-1].title = tuple[3]
            self.objectstack.append(tuple[1])
        elif tuple[1] == 'TEXT':
            self.handle_text(tuple[3])
        elif tuple[1] == 'CONT':
            self.handle_continue(tuple[3])
        elif tuple[1] == 'CONC':
            self.handle_concat(tuple[3])
        elif tuple[1] == 'FILE':
            self.handle_filename(tuple[3])
        # Source specific structure elements
        elif tuple[1] == 'AUTH':
            self.handle_originator(tuple[3])
        elif tuple[1] == 'PUBL':
            self.handle_publication(tuple[3])
        # Nothing to do
        elif tuple[1] in ('ABBR'):
            self.objectstack.append(tuple[1])
        
        
        # ######################################################################
        # Level 0
        # ######################################################################
        elif tuple[0] == 0:
            if tuple[1] == 'HEAD':
                self.familyTree = FamilyTree()
                self.objectstack.append(self.familyTree)
            elif tuple[1] == 'INDI':
                self.read_individual(tuple[2])
            elif tuple[1] == 'FAM':
                self.read_family(tuple[2])
            elif tuple[1] == 'SOUR':
                self.read_source(tuple[2])
            elif tuple[1] == 'NOTE':
                self.read_note(tuple[2], tuple[3])
            elif tuple[1] == 'SUBM':
                self.read_submitter(tuple[2])
            elif tuple[1] == 'TRLR':
                pass
            else:
                print('not handled', tuple)
                self.objectstack.append(tuple[1])
            
        # ######################################################################
        # Level 1
        # ######################################################################
        elif tuple[0] == 1:
            if tuple[1] == 'NAME':
                self.handle_name(tuple[3])
            # Spouse of a family (father or mother)
            elif tuple[1] == 'FAMS':
                family = self.read_family(tuple[2])
                self.objectstack[-2].familyspouse.append(family)
            elif tuple[1] == 'HUSB':
                individual = self.read_individual(tuple[2])
                self.objectstack[-2].husband = individual
            elif tuple[1] == 'WIFE':
                individual = self.read_individual(tuple[2])
                self.objectstack[-2].wife = individual
            elif tuple[1] == 'CHIL':
                individual = self.read_individual(tuple[2])
                self.objectstack[-2].children.append(individual)
            elif tuple[1] == 'SOUR':
                if isinstance(self.objectstack[-1], FamilyTree):
                    source = FamilyTreeSource()
                    source.system_id = tuple[3]
                    self.objectstack[-1].source = source
                    self.objectstack.append(source)
                else:
                    source = self.read_source(tuple[2])
                    self.objectstack[-2].sources.append(source)
            elif tuple[1] == 'COPR':
                self.objectstack[-1].copyright = tuple[3]
                self.objectstack.append(tuple[1])
            elif tuple[1] == 'GEDC':
                info = GedcomInfo()
                self.objectstack[-1].info = info
                self.objectstack.append(info)
            elif tuple[1] == 'CHAR':
                self.objectstack[-1].charset = tuple[3]
                self.objectstack.append(tuple[1])
            elif tuple[1] == 'LANG':
                self.objectstack[-1].langage = tuple[3]
                self.objectstack.append(tuple[1])
            elif tuple[1] == 'OBJE':
                anobject = Object(None)
                self.objectstack[-1].objects.append(anobject)
                self.objectstack.append(anobject)
            elif tuple[1] == 'SUBM':
                submitter = self.read_submitter(tuple[2])
            elif tuple[1] == 'OCCU':
                event = Event()
                event.type = 'OCCU'
                event.text = tuple[3]
                self.objectstack[-1].events.append(event)
                self.objectstack.append(event)
            elif tuple[1] == 'NOTE':
                note = self.read_note(tuple[2], tuple[3])
            else:
                print('not handled', tuple)
                self.objectstack.append(tuple[1])
            
        # ######################################################################
        # Level 2
        # ######################################################################
        elif tuple[0] == 2:
            if tuple[1] == 'NAME':
                self.objectstack[-1].name = tuple[3]
                self.objectstack.append(tuple[3])
            # firstname of an individual
            elif tuple[1] == 'GIVN':
                self.objectstack[-1].firstname = tuple[3]
                self.objectstack.append(tuple[3])
            # last name of an individual
            elif tuple[1] == 'SURN':
                self.objectstack[-1].lastname = tuple[3]
                self.objectstack.append(tuple[3])
            # last name prefix of an individual
            elif tuple[1] == 'SPFX':
                self.objectstack[-1].firstname_prefix = tuple[3]
                self.objectstack.append(tuple[3])
            # prefix of an individual name
            elif tuple[1] == 'NPFX':
                self.objectstack[-1].prefix = tuple[3]
                self.objectstack.append(tuple[3])
            # suffix of an individual name
            elif tuple[1] == 'NSFX':
                self.objectstack[-1].suffix = tuple[3]
                self.objectstack.append(tuple[3])
            # nickname of an individual name
            elif tuple[1] == 'NICK':
                self.objectstack[-1].nickname = tuple[3]
                self.objectstack.append(tuple[3])
            # a place (for events...)
            elif tuple[1] == 'PLAC':
                place = self.objectstack[-1].place = Place()
                place.place = tuple[3]
                self.objectstack.append(place)
            elif tuple[1] == 'NOTE':
                note = self.read_note(tuple[2], tuple[3])
            elif tuple[1] == 'FORM':
                self.objectstack[-1].format = tuple[3]
                self.objectstack.append(tuple[3])
            elif tuple[1] == 'DATA':
                data = SourceData()
                self.objectstack[-1].data = data
                self.objectstack.append(data)
            elif tuple[1] == 'SOUR':
                source = self.read_source(tuple[2])
                self.objectstack[-2].sources.append(source)
            elif tuple[1] == 'CORP':
                corporation = Corporation()
                corporation.name = tuple[3]
                self.objectstack[-1].corporation = corporation
                self.objectstack.append(corporation)
            elif tuple[1] == 'TIME':
                self.read_time(tuple[3])
                self.objectstack.append(tuple[1])
            elif tuple[1] == 'QUAY':
                self.objectstack[-1].certainty = tuple[3]
                self.objectstack.append(tuple[3])
            else:
                print('not handled', tuple)
                self.objectstack.append(tuple[1])

        # ######################################################################
        # Level 3
        # ######################################################################
        elif tuple[0] == 3:
            # a time (for events...)
            if tuple[1] == 'TIME':
                self.parse_time(self.objectstack[-1], tuple[3])
                self.objectstack.append(tuple[3])
            # a map infos for a place
            elif tuple[1] == 'MAP':
                amap = self.objectstack[-1].mapplace = Map()
                self.objectstack.append(amap)
            elif tuple[1] == 'QUAY':
                self.objectstack[-1].certainty = tuple[3]
                self.objectstack.append(tuple[3])
            elif tuple[1] == 'DATA':
                data = SourceData()
                self.objectstack[-1].data = data
                self.objectstack.append(data)
            else:
                print('not handled', tuple)
                self.objectstack.append(tuple[1])
                
        # ######################################################################
        # Level 4
        # ######################################################################
        elif tuple[0] == 4:
            # latitude for map
            if tuple[1] == 'LATI':
                self.objectstack[-1].latitude = float(tuple[3])
                self.objectstack.append(float(tuple[3]))
            # longitude for map
            elif tuple[1] == 'LONG':
                self.objectstack[-1].longitude = float(tuple[3])
                self.objectstack.append(float(tuple[3]))
            else:
                print('not handled', tuple)
                self.objectstack.append(tuple[1])
        else:
            print('not handled', tuple)
            self.objectstack.append(tuple[1])
